<?php

namespace App\Exceptions;

use App\Constants\ErrorCode;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Contracts\Cache\LockTimeoutException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\Exceptions\ThrottleRequestsException;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Throwable;

class Handler extends ExceptionHandler
{
    /**
     * The list of the inputs that are never flashed to the session on validation exceptions.
     *
     * @var array<int, string>
     */
    protected $dontFlash = [
        'current_password',
        'password',
        'password_confirmation',
    ];

    /**
     * A list of the exception types that are not reported.
     *
     * @var array<int, class-string<Throwable>>
     */
    protected $dontReport = [
        ServiceException::class
    ];

    /**
     * Register the exception handling callbacks for the application.
     */
    public function register(): void
    {
        $this->reportable(function (Throwable $e) {
            //
        });
    }

    public function render($request, Throwable $e)
    {
        $errCode = ErrorCode::CODE_ERROR_0 !== $e->getCode() ? $e->getCode() : ErrorCode::CODE_ERROR;
        $message = '';

        // 路由校验
        if ($e instanceof NotFoundHttpException || $e instanceof MethodNotAllowedHttpException) {
            $errCode = ErrorCode::CODE_ERROR_404;
        }

        // 登录校验
        if ($e instanceof AuthenticationException || $e instanceof UnauthorizedHttpException) {
            $errCode = ErrorCode::CODE_ERROR_401;
            $message = '请登录后重试';
        }

        // 限流校验
        if ($e instanceof HttpResponseException) {
            $message = $e->getResponse()->getContent();
        }

        // 参数校验
        if ($e instanceof ValidationException) {
            $errCode = ErrorCode::CODE_ERROR_422;
            $message = collect($e->errors())->first()[0];
        }

        //访问限制校验
        if ($e instanceof HttpException && ErrorCode::CODE_ERROR_403 === $e->getStatusCode()) {
            $errCode = ErrorCode::CODE_ERROR_403;
        }

        // 判断返回信息是否存在mysql关键字
        if (false !== stripos($e->getMessage(), 'SQLSTATE')) {
            $errCode = ErrorCode::CODE_ERROR;
            $message = '数据操作异常,请联系开发人员!';
        }

        if ($e instanceof LockTimeoutException) {
            $message = '请求过于频繁,请稍后重试';
        }

        if ($e instanceof ModelNotFoundException) {
            $message = '数据不存在';
        }

        if ($e instanceof ThrottleRequestsException ) {
            $errCode = ErrorCode::CODE_ERROR_429;
            $message = '休息一下,请求太频繁了';
        }

        if ($e instanceof BindMobileException ) {
            $errCode = ErrorCode::CODE_ERROR_409;
            $message = '请绑定手机号';
        }

        $response = [
            'code' => $errCode,
            'message' => !empty($message) ? $message : $e->getMessage(),
        ];
        if (is_develop()) {
            $response['error'] = $message ?: $e->getMessage();
//            $response['trace'] = $e->getTrace();
            $response['trace'] = array_map(function($trace) {
                return array_map(function($item) {
                    return is_string($item) ? $item : json_encode($item, JSON_UNESCAPED_UNICODE);
                }, $trace);
            }, $e->getTrace());
        }

        return response($response);
    }
}
